package com.market.manager;

import java.util.List;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.market.domain.Order;
import com.market.domain.OrderDetail;
import com.market.domain.transients.OrderQuery;

public interface OrderManager extends GenericManager<Order, Long> {
	/**
	 * This method fetch all order details of specific order
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED,readOnly=true)
	public List<OrderDetail> fetchDetails(Order order);
	
	/**
	 * This method fetch all orders satisfy specific Query
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED,readOnly=true)
	public List<Order> fetchOrders(OrderQuery orderQuery);
	
	
	/**
	 * Invoke this method when user place an order online. Not only consider save this order to database, but also
	 * minus credit from user's account first and then add an record to AccountRecord, if there are any amount paid 
	 * by user' account credit. The last is store this order
	 * This method will new a transaction, the store method it invoke will also run in this transaction.
	 * Because store method's propagation is Propagation.REQUIRED 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=RuntimeException.class )
	public Order userStore(Order order);
	

	/**
	 * This method confirm an order to database(Set order's status to Confirmed), if the order status is
	 * received, only minus inventory. If the status is new save this order and minus inventory. If the 
	 * delivered price and delivered quantity is not set (Still zero), ordered price and order quantity will
	 *  be copied to them.
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order confirm(Order order);
	
	/**
	 * This method minus credit from user's account first and then add an record to AccountRecord
	 * The last is confirm this order
	 * This method will new a transaction, the confirm method it invoke will also run in this transaction.
	 * Because confirm method's propagation is Propagation.REQUIRED 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=RuntimeException.class )
	public Order userConfirm(Order order);
	
	/**
	 * This method unConfirm an order(Set the order's status to Received), To invoke this method,this order's status
	 * must be Confirmed.
	 * The delivered quantity will be restore to inventory, and delivered price and quantity will be set to zero.
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order unConfirm(Order order);
	/**
	 * This method set order's status to Prepared and set preparedDate to current time, then save order.
	 * All order details will be saved to database too,Normally, user will input delivered price and delivered
	 * quantity.
	 * PREPARED status means this order is ready for delivery.
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order prepare(Order order);
	
	/**
	 * This method set order's status from Prepared to Confirmed, then save it.
	 * Order details will be left unchanged.
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order unPrepare(Order order);
	
	/**
	 * This method set order's status to delivered and deliveredDate to current time, then save order.
	 * Other information will be left unchanged
	 * DELIVERED status means this order have delivered to drop-off location.
	 * @param order
	 * @return
	 */	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order deliver(Order order);
	
	/**
	 * This method set order's status back to Prepared and deliveredDate to null, then save order.
	 * Other information will be left unchanged.
	 * 
	 * @param order
	 * @return
	 */	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order unDeliver(Order order);
	
	/**
	 * This method set order's status to Picked_Up and pickedupDate to current time, then save order
	 * Othe information will be left unchanged.
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order pickup(Order order);
	
	/**
	 * This method set order's status back to Delivered and pickedDate to null, then save order.
	 * Othe information will be left unchanged.
	 * @param order
	 * @return
	 */
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order unPickup(Order order);
	
	/**
	 * This method set order's status to Paid and paidDate to current time, the most important thing
	 * is user have to input paidAmount and discountAmount, then save  order
	 * if paidAmount + discountAmount - deliveredAmount is not zero, then this amount will be add to 
	 * customer's balance.
	 * 
	 * If those dates (include preparedDate,deliveredDate,pickedupDate) are null, will be set to current
	 * time. 
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order pay(Order order);
	
	/**
	 * This method set order's status back to Picked_Up and paidDate back to null.
	 * if paidAmount + discountAmount - deliveredAmount is not zero, then this amount will be removed from
	 * customer's balance. Then the paidAmount and discountAmount will be set to zero.
	 * 
	 * @param order
	 * @return
	 */	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order unPay(Order order);
	
	/**
	 * This method set order's status to Canceled and set cancelDate to current time, then save order.
	 * Other information will be left unchanged.
	 * @param order
	 * @return
	 */
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order cancel(Order order);
	
	/**
	 * This method will restore an order from Canceled state to Received State,
	 * order's status will be set to Received and orderedDate will be set to current time.
	 * All other date will be to null.
	 * @param order
	 * @return
	 */
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor=RuntimeException.class )
	public Order restore(Order order);
	
	
}
